/**
 * Created by zhangbo on 20/12/17.
 */

var ViewFrustum = (function () {
	function _(scene, opt) {
		var option = this._option = opt || {
			fov: 60,
			aspectRatio: 50/45,
			near: 0.1,
			far: 1000.0
		};
		this._scene = scene;
        this._planesPrimitives = [];
        this._outlinePrimitives = [];
        this._scratchSplits = [1.0, 100000.0];
        this._frustumSplits = [];
        this._frustum = new Cesium.PerspectiveFrustum({
            fov: Cesium.Math.toRadians(option.fov),
            aspectRatio: option.aspectRatio,
            near: option.near,
            far: option.far
        });
        this._frustumSplits[0] = this._frustum.near;
        this._frustumSplits[1] = this._frustum.far;
        this._numFrustums = 1;
        this._planesPrimitives.length = this._outlinePrimitives.length = this._numFrustums;
	}
	_.prototype.clear = function(){
		var planesPrimitives = this._planesPrimitives;
		var outlinePrimitives = this._outlinePrimitives;
		var length = planesPrimitives.length;
		for (i = 0; i < length; ++i) {
			viewer.scene.primitives.remove(outlinePrimitives[i]);
			viewer.scene.primitives.remove(planesPrimitives[i]);
			outlinePrimitives[i] = outlinePrimitives[i] && outlinePrimitives[i].destroy();
            planesPrimitives[i] = planesPrimitives[i] && planesPrimitives[i].destroy();
		}
		planesPrimitives.length = 0;
        outlinePrimitives.length = 0;
	};
	_.prototype.buildViewFrustumByVector = function(origin, end){
		if(Cesium.defined(origin) && Cesium.defined(end)){
			var velocityResult = new Cesium.Cartesian3();
	        var velocity = Cesium.Cartesian3.subtract(end, origin, velocityResult);
	        Cesium.Cartesian3.normalize(velocity, velocityResult);
	        Cesium.Cartesian3.divideByScalar(velocity, 1, velocityResult);

	        var rotationScratch = new Cesium.Matrix3();
	        Cesium.Transforms.rotationMatrixFromPositionVelocity(origin, velocityResult, Cesium.Ellipsoid.WGS84, rotationScratch);
	        var rotation = new Cesium.Matrix3();
	        Cesium.Matrix3.setColumn(rotation, 0, Cesium.Matrix3.getColumn(rotationScratch, 1, new Cesium.Cartesian3()), rotation);
	        Cesium.Matrix3.setColumn(rotation, 1, Cesium.Matrix3.getColumn(rotationScratch, 2, new Cesium.Cartesian3()), rotation);
	        Cesium.Matrix3.setColumn(rotation, 2, Cesium.Matrix3.getColumn(rotationScratch, 0, new Cesium.Cartesian3()), rotation);
	        var orientation = Cesium.Quaternion.fromRotationMatrix(rotation, new Cesium.Quaternion());
	        
//	    	var frustum = viewer.scene.camera.frustum.clone();
	        var scratchRight = new Cesium.Cartesian3();
	        var scratchRotation = new Cesium.Matrix3();
	        var scratchOrientation = new Cesium.Quaternion();
	        var scratchPerspective = new Cesium.PerspectiveFrustum();
	        var scratchPerspectiveOffCenter = new Cesium.PerspectiveOffCenterFrustum();
	        var scratchOrthographic = new Cesium.OrthographicFrustum();
	        var scratchOrthographicOffCenter = new Cesium.OrthographicOffCenterFrustum();
	        
	        var scratchColor = new Cesium.Color();
	        var frustum;
	        frustum = this._frustum.clone(frustum);
	        for (var i = 0; i < this._numFrustums; ++i) {
	            frustum.near = this._frustumSplits[i];
	            frustum.far = this._frustumSplits[i + 1];

	            this._planesPrimitives.push(viewer.scene.primitives.add(new Cesium.Primitive({
	                geometryInstances : new Cesium.GeometryInstance({
	                    geometry : new Cesium.FrustumGeometry({
	                        origin : origin,
	                        orientation : orientation,
	                        frustum : frustum,
	                        _drawNearPlane : i === 0
	                    }),
	                    attributes : {
	                        color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromAlpha(Cesium.Color.CYAN, 0.1, scratchColor))
	                    },
	                    id : 'view-frustum',
//	                    pickPrimitive : planesPrimitives[i]
	                }),
	                appearance : new Cesium.PerInstanceColorAppearance({
	                    translucent : true,
	                    flat : true
	                }),
	                asynchronous : false
	            })));

	            this._outlinePrimitives.push(viewer.scene.primitives.add(new Cesium.Primitive({
	                geometryInstances : new Cesium.GeometryInstance({
	                    geometry : new Cesium.FrustumOutlineGeometry({
	                        origin : origin,
	                        orientation : orientation,
	                        frustum : frustum,
	                        _drawNearPlane : i === 0
	                    }),
	                    attributes : {
	                        color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.CYAN)
	                    },
	                    id : 'view-frustum-outline',
//	                    pickPrimitive : planesPrimitives[i]
	                }),
	                appearance : new Cesium.PerInstanceColorAppearance({
	                    translucent : false,
	                    flat : true
	                }),
	                asynchronous : false
	            })));
	        }
		}
	};
	
	_.prototype.buildViewFrustumByHpr = function(origin, hpr){
		if(Cesium.defined(origin) && Cesium.defined(hpr)){
			var orientation = new Cesium.Quaternion();
			var heading = Cesium.Math.toRadians(hpr.heading);
	    	var pitch = Cesium.Math.toRadians(hpr.pitch + 270);
	    	var roll = Cesium.Math.toRadians(hpr.roll);
//			var transform = Cesium.Transforms.localFrameToFixedFrameGenerator('north', 'west');
			var transform = Cesium.Transforms.eastNorthUpToFixedFrame
			orientation = Cesium.Transforms.headingPitchRollQuaternion(origin, new Cesium.HeadingPitchRoll(heading, pitch, roll), Cesium.Ellipsoid.WGS84, transform, orientation);
			var rotationScratch = new Cesium.Matrix4();
			Cesium.Transforms.headingPitchRollToFixedFrame(origin, new Cesium.HeadingPitchRoll(heading, pitch, roll), Cesium.Ellipsoid.WGS84, transform, rotationScratch);
//			var rotationScratch = new Cesium.Matrix3();
//			rotationScratch = Cesium.Matrix3.fromHeadingPitchRoll(headingPitchRoll, rotationScratch);
			var direction = Cesium.Matrix4.getColumn(rotationScratch, 0, new Cesium.Cartesian4());
			var right = Cesium.Matrix4.getColumn(rotationScratch, 1, new Cesium.Cartesian4());
            var up = Cesium.Matrix4.getColumn(rotationScratch, 2, new Cesium.Cartesian4());
            direction = Cesium.Cartesian4.negate(direction, new Cesium.Cartesian4());
            right = Cesium.Cartesian4.negate(right, new Cesium.Cartesian4());
			var rotation = new Cesium.Matrix3();
	        Cesium.Matrix3.setColumn(rotation, 0, Cesium.Cartesian3.fromCartesian4(up), rotation);
	        Cesium.Matrix3.setColumn(rotation, 1, Cesium.Cartesian3.fromCartesian4(right), rotation);
	        Cesium.Matrix3.setColumn(rotation, 2, Cesium.Cartesian3.fromCartesian4(direction), rotation);
//	        Cesium.Quaternion.fromRotationMatrix(rotation, orientation);     
//	        var orientation = Cesium.Quaternion.fromHeadingPitchRoll(headingPitchRoll, new Cesium.Quaternion())
	        
	        var camera = viewer.scene.camera;
	        var frameState = viewer.scene._frameState;
//	    	var frustum = viewer.scene.camera.frustum.clone();
	        var scratchRight = new Cesium.Cartesian3();
	        var scratchRotation = new Cesium.Matrix3();
	        var scratchOrientation = new Cesium.Quaternion();
	        var scratchPerspective = new Cesium.PerspectiveFrustum();
	        var scratchPerspectiveOffCenter = new Cesium.PerspectiveOffCenterFrustum();
	        var scratchOrthographic = new Cesium.OrthographicFrustum();
	        var scratchOrthographicOffCenter = new Cesium.OrthographicOffCenterFrustum();
	        
	        var scratchColor = new Cesium.Color();
	        var frustum;
	        frustum = this._frustum.clone(frustum);
	        for (var i = 0; i < this._numFrustums; ++i) {
	            frustum.near = this._frustumSplits[i];
	            frustum.far = this._frustumSplits[i + 1];

	            this._planesPrimitives.push(viewer.scene.primitives.add(new Cesium.Primitive({
	                geometryInstances : new Cesium.GeometryInstance({
	                    geometry : new Cesium.FrustumGeometry({
	                        origin : origin,
	                        orientation : orientation,
	                        frustum : frustum,
	                        _drawNearPlane : i === 0
	                    }),
	                    attributes : {
	                        color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromAlpha(Cesium.Color.CYAN, 0.1, scratchColor))
	                    },
	                    id : 'view-frustum',
//	                    pickPrimitive : planesPrimitives[i]
	                }),
	                appearance : new Cesium.PerInstanceColorAppearance({
	                    translucent : true,
	                    flat : true
	                }),
	                asynchronous : false
	            })));

	            this._outlinePrimitives.push(viewer.scene.primitives.add(new Cesium.Primitive({
	                geometryInstances : new Cesium.GeometryInstance({
	                    geometry : new Cesium.FrustumOutlineGeometry({
	                        origin : origin,
	                        orientation : orientation,
	                        frustum : frustum,
	                        _drawNearPlane : i === 0
	                    }),
	                    attributes : {
	                        color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.CYAN)
	                    },
	                    id : 'view-frustum-outline',
//	                    pickPrimitive : planesPrimitives[i]
	                }),
	                appearance : new Cesium.PerInstanceColorAppearance({
	                    translucent : false,
	                    flat : true
	                }),
	                asynchronous : false
	            })));
	        }
		}
	};
	
	return _;
})();